﻿/******************************************************************** 
 * Cerebrum Embedded System Design Automation Framework
 * Copyright (C) 2010  The Pennsylvania State University
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 ********************************************************************/
/******************************************************************** 
 * FalconXPSBuilderConfig.cs
 * Name: Matthew Cotter
 * Date: 29 Jun 2010 
 * Description: This class implements the functions and methods required to utilize the FalconXPSBuilder library to build an aribitrary number of independent platform projects.
 * History: 
 * >> ( 9 May 2010) Matthew Cotter: Added support for Platform-specified top-level ports to facilitate connections between required components.
 * >> (15 Feb 2010) Matthew Cotter: Overhaul as part of code reorganization to facilitate uniform access to/from Component/Core objects.
 *                                      Reorganized and reordered parsing of files and properties to eliminate multiple object classes and repeated reading and rewriting of MHS file.
 * >> (27 Jan 2011) Matthew Cotter: Removed address validation from tool flow.  Retrieval of remote MPD files is still required by UCF generation, however.
 * >> (24 Aug 2010) Matthew Cotter: Added code to forcibly remove local and remote project pcores at each build.
 *                                  Added support to force a "clean", ensuring that ALL XPS Project files are removed--both locally and remotely.
 * >> (13 Aug 2010) Matthew Cotter: Updated code that handles loading of Platform files to use new hierarchical location and format of platforms 
 *                                    (paths.ProjectPlatform -> paths.Platforms\<Platform>\<Platform.xml> -> 
 *                                      paths.Platforms\<Platform>\<Board>\<Board>.xml -> paths.Platforms\<Platform>\<Board>\<fpga>\<fpga>.xml.
 * >> ( 7 Jul 2010): Updated Status messages in output.
 * >> ( 6 Jul 2010): Updated LoadPlatforms() to handle hierarchical format of system platform.
 * >> ( 1 Jul 2010): Added address space verification to project generation flow.
 * >> (29 Jun 2010): Source file created -- Initial version.
 ********************************************************************/

//#define ADDRESS_VALIDATION

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Diagnostics;
using System.IO;
using FalconPathManager;
using FalconGlobal;
using CerebrumSharedClasses;
using CerebrumSharedClasses.Platform_Details;
using System.Threading;
using System.Collections;
using CerebrumNetronObjects;

namespace FalconXpsBuilder
{
    /// <summary>
    /// Class to manage the control of the XpsBuilder class to build multiple projects for a single Cerebrum project.
    /// </summary>
    /// <seealso href="https://www.cse.psu.edu/svn/mdl/falcon_repository/trunk/Software/Cerebrum/Documentation/XpsBuilder Specification.pdf">
    /// XPS Builder Documentation</seealso>
    public class FalconXPSBuilderControl
    {
        /// <summary>
        /// Event fired when a message has been generated by the library
        /// </summary>
        public event MessageEventDelegate MessageEvent;
        /// <summary>
        /// Raises an event indicating that a message has been generated.
        /// </summary>
        /// <param name="Message">The message to be transmitted</param>
        public void RaiseMessageEvent(string Message)
        {
            if (MessageEvent != null)
            {
                MessageEvent(Message);
            }
            else
            {
                Console.WriteLine(Message);
            }
        }


        private XpsBuilder _Builder = null;
        private FalconServer _buildServer = null;

        private LinkedList<FalconServer> _Servers;
        private LinkedListNode<FalconServer> _nextServer;
        private FalconServer GetNextServer()
        {
            if (_nextServer == null)
            {
                _nextServer = _Servers.First;
            }
            else
            {
                _nextServer = _nextServer.Next;
                if (_nextServer == null)
                    _nextServer = _Servers.First;
            }

            if (_nextServer != null)
                return _nextServer.Value;
            else
                return null;
        }
        private PathManager _PathMan;

        private List<FPGA> _PlatformFPGAs;

        /// <summary>
        /// Event that fires to request a password from an external source.  If this event is not attached,
        /// the password is requested from the console.
        /// </summary>
        public PasswordRequestDelegate OnRequirePassword;


        /// <summary>
        /// Default constructor.  Initializes the internal XpsBuilder class and the list of synthesis servers to an empty list.
        /// </summary>
        public FalconXPSBuilderControl()
        {
            _Builder = new XpsBuilder();
            _Builder.MessageEvent += new MessageEventDelegate(this.RaiseMessageEvent);
            _Servers = new LinkedList<FalconServer>();
            this.AllowEmptySynth = false;
            this.ForceClean = false;
        }

        /// <summary>
        /// Get or set whether the XpsBuilder will allow the synthesis of an "empty" system; one with only base system cores.
        /// </summary>
        public bool AllowEmptySynth { get; set; }

        /// <summary>
        /// Get or set whether the XPS Projects are forcibly erased prior to building.  If false, existing files may be left in tact.   If true, existing files WILL BE REMOVED.
        /// </summary>
        public bool ForceClean { get; set; }

        /// <summary>
        /// Loads an XML file specifying the synthesis servers to be used for synthesis.
        /// </summary>
        /// <param name="ServerFile">The path to the XML file specifying the server list.</param>
        /// <returns>True if the loading was successful, False otherwise.</returns>
        /// <seealso href="https://www.cse.psu.edu/svn/mdl/falcon_repository/trunk/Software/Cerebrum/Documentation/ProjectXML.pdf">
        /// Project XML File Documentation (Cerebrum Project Files, Servers)</seealso>
        public bool LoadSynthesisServers(string ServerFile)
        {
            try
            {
                if (!File.Exists(ServerFile))
                    return false;

                _Servers = new LinkedList<FalconServer>();
                _Servers.Clear();
                XmlDocument xDoc = new XmlDocument();
                xDoc.Load(ServerFile);

                foreach (XmlNode xElem in xDoc.ChildNodes)
                {
                    if (xElem.Name.ToLower() == "servers")
                    {
                        ReadServers(xElem);
                        break;
                    }
                }

            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
                return false;
            }
            _Builder.RaiseMessageEvent("Loaded Servers from: {0}", ServerFile);
            _buildServer = GetNextServer();
            return true;
        }
        private void ReadServers(XmlNode TopNode)
        {
            foreach (XmlNode xENode in TopNode.ChildNodes)
            {
                if (xENode.Name.ToLower() == "server")
                {
                    FalconServer fs = new FalconServer();
                    fs.ParseServerNode(xENode);
                    _Servers.AddLast(fs);
                }
            }
        }

        /// <summary>
        /// Loads a list of named paths from the specified file into a FalconPathManager for local access.
        /// </summary>
        /// <param name="PathFile">The path to the XML file from which paths are to be loaded.</param>
        /// <returns>True if loading the paths was successful, false otherwise.</returns>
        /// <seealso href="https://www.cse.psu.edu/svn/mdl/falcon_repository/trunk/Software/Cerebrum/Documentation/ProjectXML.pdf">
        /// Project XML File Documentation (Cerebrum Project Files, Project Paths)</seealso>
        public bool LoadPaths(string PathFile)
        {
            try
            {
                _PathMan = new PathManager(PathFile);
                _Builder.RaiseMessageEvent("Loaded Paths from: {0}", PathFile);
                return true;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }


        /// <summary>
        /// Loads the individual FPGA platforms from the master platform file.
        /// </summary>
        /// <returns>True if loading the platforms was successful, false otherwise.</returns>
        /// <seealso href="https://www.cse.psu.edu/svn/mdl/falcon_repository/trunk/Software/Cerebrum/Documentation/ProjectXML.pdf">
        /// Project XML File Documentation (Cerebrum Project Files, Platform)</seealso>
        /// <seealso href="https://www.cse.psu.edu/svn/mdl/falcon_repository/trunk/Software/Cerebrum/Documentation/Platform XML Specifications.pdf">
        /// Platform XML File Documentation</seealso>
        public bool LoadPlatformFile()
        {
            try
            {
                FileInfo PlatformFile = new FileInfo(String.Format(@"{0}\{1}\{1}.xml", _PathMan["Platforms"], _PathMan["ProjectPlatform"]));
                if (!PlatformFile.Exists)
                    return false;
                XmlDocument xDoc = new XmlDocument();
                xDoc.Load(PlatformFile.FullName);
                _PlatformFPGAs = new List<FPGA>();
                _PlatformFPGAs.Clear();

                foreach (XmlNode xElem in xDoc.ChildNodes)
                {
                    if (xElem.Name.ToLower() == "platform")
                    {
                        foreach (XmlNode xBoardNode in xElem.ChildNodes)
                        {
                            if (xBoardNode.Name.ToLower() == "board")
                            {
                                string boardFile = string.Empty;
                                string boardID = string.Empty;
                                foreach (XmlAttribute xAttr in xBoardNode.Attributes)
                                {
                                    if (xAttr.Name.ToLower() == "file")
                                    {
                                        boardFile = xAttr.Value;
                                    }
                                    else if (xAttr.Name.ToLower() == "id")
                                    {
                                        boardID = xAttr.Value;
                                    }
                                }
                                if ((boardID != string.Empty) && (boardFile != string.Empty))
                                {
                                    ProcessBoard(boardID, boardFile);
                                }
                            }
                        }
                    }
                }
                _Builder.RaiseMessageEvent("Loaded Platform from: {0}", PlatformFile);
                return true;
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
                return false;
            }
        }
        private void ProcessBoard(string boardID, string BoardFileName)
        {
            string BoardShortName = BoardFileName.Substring(0, BoardFileName.IndexOf("."));
            FileInfo BoardFile = new FileInfo(String.Format(@"{0}\{1}\{2}\{2}.xml", _PathMan["Platforms"], _PathMan["ProjectPlatform"], BoardShortName));
            if (!BoardFile.Exists)
                return;

            XmlDocument xDoc = new XmlDocument();
            xDoc.Load(BoardFile.FullName);

            foreach (XmlNode xElem in xDoc.ChildNodes)
            {
                if (xElem.Name.ToLower() == "board")
                {
                    foreach (XmlNode xBoardNode in xElem.ChildNodes)
                    {
                        if (xBoardNode.Name.ToLower() == "fpga")
                        {
                            string fpgaFile = string.Empty;
                            string fpgaID = string.Empty;
                            foreach (XmlAttribute xAttr in xBoardNode.Attributes)
                            {
                                if (xAttr.Name.ToLower() == "file")
                                {
                                    fpgaFile = xAttr.Value;
                                }
                                else if (xAttr.Name.ToLower() == "id")
                                {
                                    fpgaID = xAttr.Value;
                                }
                            }
                            if ((fpgaID != string.Empty) && (fpgaFile != string.Empty))
                            {
                                FPGA thisFPGA = ProcessFPGA(boardID, BoardShortName, fpgaID, fpgaFile);
                                foreach (XmlNode xExtPortNode in xBoardNode.ChildNodes)
                                {
                                    if (String.Compare(xExtPortNode.Name, "ExternalPort", true) == 0)
                                    {
                                        FPGA_External_Port EP = new FPGA_External_Port(xExtPortNode);
                                        thisFPGA.ExternalPorts.Add(EP);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        private FPGA ProcessFPGA(string boardID, string BoardShortName, string FPGAID, string FPGAFileName)
        {
            string FPGAShortName = FPGAFileName.Substring(0, FPGAFileName.IndexOf("."));
            FileInfo FPGAFile = new FileInfo(String.Format(@"{0}\{1}\{2}\{3}\{3}.xml", _PathMan["Platforms"], _PathMan["ProjectPlatform"], BoardShortName, FPGAShortName));
            if (!FPGAFile.Exists)
                return null;

            FPGA fpga = new FPGA();
            if (fpga.ParseFPGADoc(FPGAFile.FullName))
            {
                fpga.Instance = boardID + "." + FPGAID;
                fpga.SourceFile = FPGAFile.FullName;
                _PlatformFPGAs.Add(fpga);
            }
            return fpga;
        }

        /// <summary>
        /// Uses the XpsBuilder class to configure, verify, and build each FPGA project in preparation for synthesis.
        /// </summary>
        /// <param name="Servers">The file containing the set of synthesis servers on which the XPS projects will be synthesized.</param>
        /// <param name="Design">The system design file that specifies information about all of the cores that are to be integrated into the XPS projects.</param>
        /// <returns>True if successful, False if an error occurs.</returns>
        public bool ConfigureAndBuild(string Servers, string Design)
        {
            try
            {
                string Platform = String.Format(@"{0}\{1}\{1}.xml", _PathMan["Platforms"], _PathMan["ProjectPlatform"]);
                if ((!File.Exists(Servers)) && (!Servers.Contains("\\")))
                    Servers = _PathMan.GetPath("LocalProjectRoot") + "\\" + Servers;
                if ((!File.Exists(Design)) && (!Design.Contains("\\")))
                    Design = _PathMan.GetPath("LocalProjectRoot") + "\\" + Design;

                if (!File.Exists(Servers))
                {
                    _Builder.RaiseMessageEvent("ERROR: Unable to open Servers file {0}", Servers);
                    return false;
                }
                if (!File.Exists(Platform))
                {
                    _Builder.RaiseMessageEvent("ERROR: Unable to open Platform file {0}", Platform);
                    return false;
                }
                if (!File.Exists(Design))
                {
                    _Builder.RaiseMessageEvent("ERROR: Unable to open Design file {0}", Design);
                    return false;
                }


                string ProjectRootDir = _PathMan.GetPath("LocalProjectRoot");
                string ProjectDir = _PathMan.GetPath("LocalProject");
                string SynthDir = _PathMan.GetPath("RemoteProject");
                string TempDir = _PathMan.GetPath("ProjectTemp");

                // Load the server(s)
                if (!LoadSynthesisServers(Servers))
                {
                    _Builder.RaiseMessageEvent("ERROR: Unable to read server file: {0}", Servers);
                    return false;
                }
                _buildServer = GetNextServer();
                if (_buildServer == null)
                {
                    _Builder.RaiseMessageEvent("ERROR: No servers found in file: {0}", Servers);
                    return false;
                }

                // Load the platform
                if (!LoadPlatformFile())
                {
                    _Builder.RaiseMessageEvent("ERROR: Unable to read platform file: {0}", Platform);
                    return false;
                }
                if (_PlatformFPGAs.Count == 0)
                {
                    _Builder.RaiseMessageEvent("ERROR: No platform or boards found in file: {0}", Platform);
                    return false;
                }

                // Configure XPS Builder File Services Class
                
                
                _Builder.RaiseMessageEvent("\n\n");
                if (!Directory.Exists(ProjectDir))
                {
                    if (this.ForceClean)
                    {
                        _Builder.RaiseMessageEvent("Force-cleaning Directory: {0}", ProjectDir);
                        FileServices.CleanDirectory(ProjectDir);

                    }
                    _Builder.RaiseMessageEvent("Creating Directory: {0}", ProjectDir);
                    Directory.CreateDirectory(ProjectDir);
                }
                if (!Directory.Exists(TempDir))
                {
                    _Builder.RaiseMessageEvent("Creating Directory: {0}", TempDir);
                    Directory.CreateDirectory(TempDir);
                }
                _Builder.FileService.isLocalSynthServer = false;
                _Builder.FileService.Username = _buildServer.UserName;
                //_buildServer.Password = string.Empty;
                _Builder.FileService.Servername = _buildServer.Address;
                if ((_buildServer.Password == string.Empty) || (_buildServer.Password == null))
                {
                    if (OnRequirePassword != null)
                    {
                        _buildServer.Password = OnRequirePassword(_buildServer.UserName, _buildServer.Address);
                        if (_buildServer.Password == string.Empty)
                        {
                            RaiseMessageEvent("Authentication failure.");
                            return false;
                        }
                    }
                    else
                    {
                        _buildServer.Password = ReadPassword(_buildServer.UserName, _buildServer.Address);
                    }
                }

                _Builder.PathMan = _PathMan;
                _Builder.FileService.UserPass = _buildServer.Password;
                _Builder.FileService.LocalOSType = FileServices.OSVersion.WINDOWS;
                _Builder.FileService.remoteOSType = FileServices.OSVersion.LINUX;
                _Builder.FileService.overWriteFiles = true;
                _Builder.FileService.createFolder_ifNotExist = true;
                try
                {
                    _Builder.FileService.login();
                }
                catch
                {
                    _buildServer.Password = string.Empty;
                    _Builder.FileService.UserPass = string.Empty;
                    RaiseMessageEvent("Authentication failure.");
                    return false;
                }
                _Builder.FileService.Set_Local_Dir(ProjectDir);
                _Builder.FileService.Set_Remote_Dir(SynthDir);

                if (this.ForceClean)
                {
                    _Builder.FileService.execShell.RunCommand(String.Format("rm -rf {0}", _PathMan["RemoteProject"]));
                }
                _Builder.FileService.execShell.RunCommand(String.Format("mkdir {0}", _PathMan["RemoteProject"]));

                foreach (FPGA fpga in _PlatformFPGAs)
                {
                    _Builder.RaiseMessageEvent("-----------------------------------------------");
                    _Builder.RaiseMessageEvent("Building XPS Project for FPGA '{0}'...", fpga.Instance);
                    if (!Directory.Exists(ProjectDir + "\\" + fpga.Instance))
                        Directory.CreateDirectory(ProjectDir + "\\" + fpga.Instance);
                    if (!Directory.Exists(ProjectDir + "\\" + fpga.Instance + "\\data"))
                        Directory.CreateDirectory(ProjectDir + "\\" + fpga.Instance + "\\data");
                    if (Directory.Exists(ProjectDir + "\\" + fpga.Instance + "\\pcores"))
                    {
                        // Remove and recreate local Project PCores
                        Directory.Delete(ProjectDir + "\\" + fpga.Instance + "\\pcores", true);
                    }
                    if (!Directory.Exists(ProjectDir + "\\" + fpga.Instance + "\\pcores"))
                    {
                        Directory.CreateDirectory(ProjectDir + "\\" + fpga.Instance + "\\pcores");
                    }
                    if (!Directory.Exists(ProjectDir + "\\" + fpga.Instance + "\\implementation"))
                        Directory.CreateDirectory(ProjectDir + "\\" + fpga.Instance + "\\implementation");

                    _Builder.ProjectOpts.PCoresList.Clear();
                    _Builder.ProjectOpts.XpsProjectName = "system";
                    _Builder.ProjectOpts.PlatFormFPGAs.Clear();
                    _Builder.ProjectOpts.PlatFormFPGAs.Add(fpga.Instance);
                    _Builder.ProjectOpts.XpsProjectDirectory = ProjectDir + "\\" + fpga.Instance;
                    _Builder.CreateXPSProjects();

                    _Builder.ProjectOpts.XPSMapFile = _PathMan.GetPath("xpsmap");
                    _Builder.ProjectOpts.LoadXPSMap(_PathMan, fpga.Instance);
                    string MHSFile = _Builder.ProjectOpts.XpsProjectDirectory + "\\" + _Builder.ProjectOpts.XpsProjectName + ".mhs";

                    _Builder.RaiseMessageEvent("Retrieving PCore definition files for FPGA '{0}'...", fpga.Instance);
                    LoadCoreMPDs();
                    _Builder.RaiseMessageEvent("\tFPGA '{0}' PCore retrieval Complete!.", fpga.Instance);

                    List<string> MHSPortMaps = new List<string>();

                    _Builder.ImportCustomXMLs(_PathMan, ref MHSPortMaps);
                    
#if (ADDRESS_VALIDATION)
                    #region Address Validation
                    _Builder.RaiseMessageEvent("Validating Address Spaces for FPGA '{0}'...", fpga.Instance);
                    FalconXPSAddressVerifier AddrCheck = new FalconXPSAddressVerifier(fpga.Instance, _Builder.FileService, _PathMan, _Builder);
                    if (!AddrCheck.VerifyMHSAddresses(MHSFile, SystemBusList, Cores, Ports, ProcessorTargets))
                    {
                        _Builder.RaiseMessageEvent("ERROR: Unable to validate overlapping address ranges.");
                        throw new Exception("Cores in MHS file have been assigned overlapping or insufficient address ranges.");
                    }
                    _Builder.RaiseMessageEvent("\tFPGA '{0}' address validation Complete!", fpga.Instance);
                    #endregion
#endif

                    #region UCF Generation
                    _Builder.RaiseMessageEvent("Generating Constraints file for FPGA '{0}'...", fpga.Instance);
                    _Builder.GenerateUCF(fpga, _Builder.ProjectOpts.PCoresList, MHSPortMaps);
                    _Builder.RaiseMessageEvent("\tFPGA '{0}' constraint generation Complete!", fpga.Instance);
                    #endregion

                    // Remove remote pcores
                    string remotePCoresFolder = String.Format("{0}/{1}/pcores", _PathMan["RemoteProject"], fpga.Instance);
                    _Builder.FileService.execShell.RunCommand(String.Format("rm -rf {0}", remotePCoresFolder));
                    _Builder.RaiseMessageEvent("FPGA '{0}' build Complete!", fpga.Instance);

                    if (File.Exists(MHSFile))
                    {
                        #region Processor Identification
                        _Builder.RaiseMessageEvent("Performing processor identification for FPGA '{0}'...", fpga.Instance);
                        ProcessorEnumerator ProcEnum = new ProcessorEnumerator();
                        ProcEnum.Builder = _Builder;
                        ProcEnum.ParseMHS(MHSFile);
                        List<ProcessorEnumerator.ProcessorEntry> Procs = ProcEnum.GetProcessors();
                        string ProcessorTargets = string.Empty;
                        foreach (ProcessorEnumerator.ProcessorEntry PEntry in Procs)
                        {
                            if (PEntry.CPUNumber <= 0)
                            {
                                _Builder.RaiseMessageEvent("\n\tWARNING: Could not identify CPU Number for Processor '{0}' in FPGA '{1}'.", PEntry.Instance, fpga.Instance);
                            }
                            if ((PEntry.PowerPC) && (!ProcessorTargets.Contains("ppc")))
                            {
                                ProcessorTargets = ProcessorTargets + "ppc;";
                            }
                            else if ((!PEntry.PowerPC) && (!ProcessorTargets.Contains("mb")))
                            {
                                ProcessorTargets = ProcessorTargets + "mb;";
                            }
                        }
                        UpdateDesignProcessors(fpga.Instance, Design, Procs);
                        _Builder.RaiseMessageEvent("\tFPGA '{0}' processor identification Complete!", fpga.Instance);
                        #endregion
                    }
                    else
                    {
                        _Builder.RaiseMessageEvent("MHS File not present for {0} -- Skipping Processor Identification and Address Validation.", fpga.Instance);
                    }
                }

                _Builder.UploadCerebrumFiles(ProjectDir, SynthDir);
            }
            catch (ThreadAbortException TAEx)
            {
                ErrorReporting.ExceptionDetails(TAEx);
            }
            catch (Exception ex)
            {
                _Builder.RaiseMessageEvent(ErrorReporting.ExceptionDetails(ex));
                ErrorReporting.DebugException(ex);
                return false;
            }
            finally
            {
                try
                {
                    _Builder.FileService.logout();
                }
                catch { }
            }
            return true;
        }

        private bool LoadCoreMPDs()
        {
            try
            {
                string tempPath = _Builder.PathMan.GetPath("ProjectTemp");
                if (!Directory.Exists(tempPath))
                    Directory.CreateDirectory(tempPath);
                foreach (ComponentCore CompCore in _Builder.ProjectOpts.PCoresList)
                {
                    FileInfo coreFile = CompCore.RetrieveMPD(this._PathMan, _Builder.FileService);
                    if ((coreFile != null) && (coreFile.Exists))
                    {
                        List<CoreAddressRangeInfo> CoreInfos;
                        _Builder.ReadBusAddressParameters(coreFile.FullName, out CoreInfos, CompCore);
                        coreFile.Attributes = FileAttributes.Normal;
                        if (coreFile.FullName.Contains(tempPath))
                        {
                            try
                            {
                                coreFile.Delete();
                            }
                            catch { }
                        }
                    }
                }
                return true;
            }
            catch (Exception ex)
            {
                _Builder.RaiseMessageEvent(ex.Message);
            }
            return false;

        }

        private void UpdateDesignProcessors(string FPGAID, string DesignFilePath, List<ProcessorEnumerator.ProcessorEntry> Procs)
        {
            XmlDocument xInput = new XmlDocument();

            xInput.Load(DesignFilePath);
            foreach (XmlNode xRoot in xInput.ChildNodes)
            {
                if (xRoot.Name.ToLower() == "design")
                {
                    foreach (XmlNode xDesChild in xRoot.ChildNodes)
                    {
                        if (xDesChild.Name.ToLower() == "processors")
                        {
                            foreach (XmlNode xProcNode in xDesChild.ChildNodes)
                            {
                                if (xProcNode.Name.ToLower() == "processor")
                                {
                                    string ProcInst = string.Empty;
                                    foreach (XmlAttribute xAttr in xProcNode.Attributes)
                                    {
                                        if (string.Compare(xAttr.Name, "Instance", true) == 0)
                                        {
                                            ProcInst = xAttr.Value;
                                            break;
                                        }
                                    }
                                    if (ProcInst != string.Empty)
                                    {
                                        string TargetFPGA = string.Empty;
                                        XmlNode xOldCPU = null;
                                        XmlNode xCPUNumber = xInput.CreateElement("CPUNumber");
                                        xCPUNumber.InnerText = "-1";
                                        foreach (XmlNode xProcProp in xProcNode.ChildNodes)
                                        {
                                            if (xProcProp.Name.ToLower() == "FPGA")
                                            {
                                                TargetFPGA = xProcProp.InnerText;
                                            }
                                            if (xProcProp.Name.ToLower() == "cpunumber")
                                            {
                                                xOldCPU = xProcProp;
                                            }
                                        }
                                        if (xOldCPU != null)
                                        {
                                            xProcNode.RemoveChild(xOldCPU);
                                        }
                                        if (TargetFPGA == FPGAID)
                                        {
                                            foreach (ProcessorEnumerator.ProcessorEntry PEntry in Procs)
                                            {
                                                if (String.Compare(ProcInst, PEntry.Instance, true) == 0)
                                                {
                                                    xCPUNumber.InnerText = PEntry.CPUNumber.ToString();
                                                    break;
                                                }
                                            }
                                            xProcNode.AppendChild(xCPUNumber);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            xInput.Save(DesignFilePath);            
        }
        
        /// <summary>
        /// Reads the password for the locally specified synthesis server from the Console.  The password characters are not echoed to the console, but replaced by asterisks.
        /// </summary>
        /// <param name="user">The user name to be included in the prompt.</param>
        /// <param name="server">The server address to included in the prompt.</param>
        /// <returns>The password as read in from the Console.</returns>
        public string ReadPassword(string user, string server)
        {
            Console.Write("{0}@{1}'s password: ", user, server);
            string input = string.Empty;
            string rd;
            rd = Console.ReadKey(true).KeyChar.ToString();
            while ((rd != "\n") && (rd != "\r"))
            {
                if (rd == "\b")
                {
                    if (input.Length > 0)
                    {
                        input = input.Substring(0, input.Length - 1);
                        Console.CursorLeft = Console.CursorLeft - 1;
                        Console.Write(" ");
                        Console.CursorLeft = Console.CursorLeft - 1;
                    }
                }
                else
                {
                    input += rd;
                    Console.Write("*");
                }
                rd = Console.ReadKey(true).KeyChar.ToString();
            }
            input = input.Replace("\r", string.Empty);
            input = input.Replace("\n", string.Empty);
            Console.WriteLine();
            return input;
        }
    }
}
